import java.util.Arrays;

public class PrefixTree {
	int[] countShared;
	int[] result;
	int[] numBits;
	int[] majorBit;

	public int getNumNodes(String[] words) {
		int n = words.length;
		int[][] countLetters = new int[n][26];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < words[i].length(); j++)
				countLetters[i][words[i].charAt(j) - 'a']++;
		}
		countShared = new int[1 << n];
		for (int i = 0; i < (1 << n); i++) {
			int[] countSame = new int[26];
			Arrays.fill(countSame, Integer.MAX_VALUE);
			for (int j = 0; j < n; j++) {
				if (((i >> j) & 1) != 0) {
					for (int k = 0; k < 26; k++)
						countSame[k] = Math.min(countSame[k], countLetters[j][k]);
				}
			}
			for (int j = 0; j < 26; j++)
				countShared[i] += countSame[j];
		}
		result = new int[1 << n];
		Arrays.fill(result, -1);
		numBits = new int[1 << n];
		for (int i = 0; i < (1 << n); i++)
			numBits[i] = Integer.bitCount(i);
		majorBit = new int[1 << n];
		for (int i = 0; i < (1 << n); i++)
			majorBit[i] = Integer.highestOneBit(i);
		for (int mask = 1; mask < (1 << n); mask++) {
			if (numBits[mask] == 1) {
				result[mask] = countShared[mask];
				continue;
			}
			result[mask] = Integer.MAX_VALUE;
			for (int partMask = (mask - 1) & mask; partMask >= majorBit[mask]; partMask = (partMask - 1) & mask)
				result[mask] = Math.min(result[mask], result[partMask] + result[mask - partMask] - countShared[mask]);
		}
		return result[(1 << n) - 1] + 1;
	}

//	private int go(int mask) {
//		if (result[mask] != -1)
//			return result[mask];
//	}


	// BEGIN CUT HERE
	public static void main(String[] args) {
		if (args.length == 0) {
			PrefixTreeHarness.run_test(-1);
		} else {
			for (int i=0; i<args.length; ++i)
				PrefixTreeHarness.run_test(Integer.valueOf(args[i]));
		}
	}
// END CUT HERE
}

// BEGIN CUT HERE
class PrefixTreeHarness {
	public static void run_test(int casenum) {
		if (casenum != -1) {
			if (runTestCase(casenum) == -1)
				System.err.println("Illegal input! Test case " + casenum + " does not exist.");
			return;
		}
		
		int correct = 0, total = 0;
		for (int i=0;; ++i) {
			int x = runTestCase(i);
			if (x == -1) {
				if (i >= 100) break;
				continue;
			}
			correct += x;
			++total;
		}
		
		if (total == 0) {
			System.err.println("No test cases run.");
		} else if (correct < total) {
			System.err.println("Some cases FAILED (passed " + correct + " of " + total + ").");
		} else {
			System.err.println("All " + total + " tests passed!");
		}
	}
	
	static boolean compareOutput(int expected, int result) { return expected == result; }
	static String formatResult(int res) {
		return String.format("%d", res);
	}
	
	static int verifyCase(int casenum, int expected, int received) { 
		System.err.print("Example " + casenum + "... ");
		if (compareOutput(expected, received)) {
			System.err.println("PASSED");
			return 1;
		} else {
			System.err.println("FAILED");
			System.err.println("    Expected: " + formatResult(expected)); 
			System.err.println("    Received: " + formatResult(received)); 
			return 0;
		}
	}

	static int runTestCase(int casenum) {
		switch(casenum) {
		case 0: {
			String[] words            = {"topcoder"};
			int expected__            = 9;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}
		case 1: {
			String[] words            = {"topcoder","topcoder"};
			int expected__            = 9;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}
		case 2: {
			String[] words            = {"aab","ca"};
			int expected__            = 5;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}
		case 3: {
			String[] words            = {"aab","ca","ba"};
			int expected__            = 5;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}
		case 4: {
			String[] words            = {"ab","cd","ef"};
			int expected__            = 7;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}
		case 5: {
			String[] words            = {"a","aa","aaa"};
			int expected__            = 4;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}

		// custom cases

/*      case 6: {
			String[] words            = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}*/
/*      case 7: {
			String[] words            = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}*/
/*      case 8: {
			String[] words            = ;
			int expected__            = ;

			return verifyCase(casenum, expected__, new PrefixTree().getNumNodes(words));
		}*/
		default:
			return -1;
		}
	}
}

// END CUT HERE
